<?php
namespace App\GameService\games;

use App\Common\GameCommon;
use App\Common\PlayCommon;
use App\Enum\SanggEnum;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use EasySwoole\EasySwoole\Task\TaskManager;
use Swoole\Timer;
use App\Utility\RedisTools;
use App\Common\BaseComm;
use App\Enum\CardEnum;
use App\Enum\SysEnum;

/**
 * 三公游戏
 *
 * @author Administrator
 */
class PlaySanGong extends BasePlay
{

    public function __construct()
    {
        //修改时间注意机器人下抢庄下注翻牌推送数据时间是否滞后
        $this-> gtimeConfig = array(
            "waitQZLong" => 5,//等待抢庄时长
            "QZLong" => 8,    //抢庄时长
            "waitBetLong" => 6,    //等待下注,如果前台不发送执行下一步,6秒后将开启下注定时器
            "betLong" => 8,        //下注时长
            "waitCardLong" => 5,   //翻牌时长
            "waitDealLong" => 8,   //发牌完成完成，等待结算时长,8秒后返回结算结果
        );
    }

    /**
     * TODO 获取最高的FD用户信息
     * @param array $downInfo
     * @param boolean $playMfd
     * @param number $maxMutl  返回最大的抢的倍数据值；
     * @return boolean|number|mixed
     */
    protected static function getGameQzMaxFd($downInfo,$playMfd = false,&$maxMutl = 1,$minZjPoints = 0){
        $lastFdVal = 0 ;
        $maxFdList = [];
        if (!isset($downInfo) || empty($downInfo) ) { return false;}
        $maxMutl = !empty($downInfo) ? max($downInfo) : FALSE;                          //取最大值==最大倍数；
        BaseEnum::Logger("计算最大倍数：(GamesCommon-getGameQzMaxFd)-中最大的FD [Fd=Array]--最大倍数：{$maxMutl}-->>>--playermoney=".json_encode($playMfd)."=>minZjPoints=".$minZjPoints, 'user-login');
        $proArr = [50,20,10,10,10,10];//达到最低庄家分数的玩家抢庄概率权重值,一般最大人数5人;
        if (isset($maxMutl) && intval($maxMutl) > 0) {      //有抢过倍数大于=1的
            $countRes   = array_count_values ($downInfo);   //对比倍数； 取最大值；
            $count_max_num = isset($countRes[$maxMutl]) ? intval($countRes[$maxMutl]) : 0 ;
            //最大数据；
            if(isset($count_max_num) && $count_max_num > 1){
                //寻找最大值的多个用户；
                BaseEnum::Logger("计算最大倍数：(getGameQzMaxFd)-找FD [Fd=Array]--抢{$maxMutl}倍数人数（ > 1）：{$count_max_num}-->>>--playermoney=".json_encode($countRes), 'user-login');
                foreach ($downInfo as $onefd => $onemax){
                    if(intval($maxMutl) === intval($onemax)){
                        $maxFdList[] = $onefd;          //最大值
                    }
                }
                $lastFdVal = !empty($maxFdList) ? reset($maxFdList) : 0 ;
                //大于2个用户抢的倍数相同；
                if (isset($playMfd) && !empty($playMfd) && !empty($maxFdList) && sizeof($maxFdList) > 1) {
                    //要排序的数组
                    $selectArr = [];
                    foreach ($maxFdList as $seatNo) {
                        $selectArr[$seatNo] = $playMfd[$seatNo] ?? 0;
                    }
                    arsort($selectArr);
                    $k = 0;
                    foreach ($selectArr as $seatNo =>$points) {
                        $selectArr[$seatNo] = $points>=$minZjPoints ? $proArr[$k] : 0;
                        $k++;
                    }
                    if(!empty($selectArr) && max($selectArr) > 0){
                        $lastFdVal = GameCommon::getPropSeat($selectArr);//有概率值大于0的
                    }else{
                        $lastFdVal = array_search(max($playMfd),$playMfd); //所有抢庄玩家都达不到最低抢庄分数，取同局最大points的座位号。
                    }
                }
            }else{
                $lastFdVal = array_search($maxMutl, $downInfo);
                if (isset($playMfd) && !empty($playMfd) && isset($playMfd[$lastFdVal]) && $playMfd[$lastFdVal]<$minZjPoints){
                    $lastFdVal = array_search(max($playMfd),$playMfd);//无法保证最小庄家分数,取同局最大points的座位号
                }
            }
        }else{
            $maxMutl = 1 ;//全都不抢
            if (isset($playMfd) && !empty($playMfd)){
                arsort($playMfd);
                $selectArr = [];
                $k = 0;
                foreach ($playMfd as $seatNo => $points) {
                    $selectArr[$seatNo] =  $points>=$minZjPoints ? $proArr[$k] : 0;
                    $k++;
                }
                $lastFdVal = GameCommon::getPropSeat($selectArr);
            }else{
                $lastFdVal = array_rand($downInfo,1);
            }
        }
        return $lastFdVal;
    }

    /**
     * TODO 计算这个房间谁坐庄(带条件限定)；
     * @param string $roomNo
     * @param array $player 主人信息
     * @param array $minZjPoints 最小的庄家分数
     * @return boolean
     */
    public  function countRoomMaimZhuang($roomNo ,$player = false ,& $notQzUser= FALSE, $minZjPoints = 0) {
        $rediskey = SysEnum::ONLINE_BDATA_KEY;
        $redisusekey = SysEnum::ONLINE_ROOMS_LIST_KEY.$roomNo;
        $zjUser = false ;
        $qzMaxMutl = 0;
        $fjDetail = BaseComm::distMemoryRooms($roomNo);                           //房间内信息
        $playerList = isset($fjDetail['lists']) ? $fjDetail['lists'] : [];      //房间内的人数
        $allPSeat = !empty($playerList) ? array_column($playerList, "seatNo") : false ;
        $player_Moneys = !empty($playerList) ? array_column($playerList, "points","seatNo"): false ;
        if(isset($fjDetail['isOpen']) && intval($fjDetail['isOpen']) === 1 && !empty($playerList) && !empty($allPSeat)){    //游戏抢庄状态
            //抢庄的倍数据REDIS值；
            $downInfo = RedisTools::Pool_hGet($rediskey,$roomNo);
            $downInfo = !empty($downInfo) ? json_decode($downInfo,true) : FALSE;
            $notQzUser = [];  //统计还有几个玩家不抢庄的；
            foreach ($allPSeat as $ssid){
                if (isset($downInfo) && !empty($downInfo) && is_array($downInfo) && array_key_exists($ssid, $downInfo)) { //查询玩家是否已下过庄
                    continue ;
                }
                $notQzUser[] = ["seatNo"=> $ssid,"mutdotts" => 0, "self"=> 1];  //不抢的主动推信息
            }
            BaseEnum::Logger("定时器计算谁坐庄：---all >>> " . json_encode($allPSeat) ."--qz:=".json_encode($downInfo), 'user-login');
            if(empty($downInfo)){ //都没抢；都为0
                $downInfo = array_column($playerList, "betmoney","seatNo") ; //取0的值
            }
            //TODO  对比倍数； 取最大值；
            $maxPfd = $this->getGameQzMaxFd($downInfo , $player_Moneys , $qzMaxMutl, $minZjPoints);
            $zjUser = isset($player[$maxPfd]) ? $player[$maxPfd] : false ;
            if ($maxPfd !== false && $maxPfd >=0  && !empty($zjUser) && isset($qzMaxMutl)) {    //找到最优秀的FD用户值；

                //计算找到庄家FD；标识为为庄家；$maxPfd＝座位号
                $playerList[$maxPfd]["mutdotts"] = $qzMaxMutl;
                $playerList[$maxPfd]["mainflag"] = 1;
                $zjUser["mutdotts"] = $qzMaxMutl;       //抢庄倍数
                BaseEnum::Logger("定时器计算谁坐庄：(countRoomMaimZhuang)-定时器计算 success 谁是庄家[seatNo={$maxPfd}]--倍数：{$qzMaxMutl}-->>> " . $roomNo ."--player=".json_encode($player_Moneys), 'user-login');

                //存储值；
                $fjDetail['fjStatus'] = CardEnum::GAME_STEP_1;              //抢庄成功，进入下注
                $fjDetail['lists'] = $playerList;

                //是否列队中还有人员
                BaseComm::distMemoryRooms($roomNo,TRUE,$fjDetail);           //保存用户数据
                BaseEnum::wirteRedisData($redisusekey,BaseEnum::JsonEncode($fjDetail));  //缓存；
                return $zjUser;
            }
        }
        return FALSE;
    }

    /**
     * 开始游戏入口；
     * 必须实现这个方法；
     * 游戏开始逻辑
     */
    public function asycStartGame($gameNo, $gameRId = FALSE, $fjInfo = FALSE, &$commonLoopTimer = 0)
    {
        $gameId = isset($fjInfo['gameId']) ? intval($fjInfo['gameId']) : 0;
        $roomEvery = isset($fjInfo['everyPoints']) ? floatval($fjInfo['everyPoints']) : 0;
        $gameAllData = BaseComm::distMemoryRooms($gameNo, FALSE); // 内存数据；
        $fjSta = isset($gameAllData['fjStatus']) ? intval($gameAllData['fjStatus']) : 0;
        $gamePlays = isset($gameAllData['lists']) ? $gameAllData['lists'] : FALSE; // 玩家列表；
        $playFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        BaseEnum::Logger('取内存数据:Games-(PlaySanGong)-[asycStartGame]--->>>' . json_encode($gameAllData), 'user-login');

        // 刚开始就给玩家生成牌的数据；
        $useCards = GameCommon::createCardList($gameId, $gameNo, false); // 启动发牌 ： XYM_0X19；

        BaseEnum::Logger("游戏开始生成牌:Games-(PlaySanGong)-{$gameId} 再计算计算谁是[{$gameNo}]庄主---->>>" . json_encode($useCards), 'user-login'); // 所有玩家FD

        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playFds,
            "status" => $fjSta
        ];
        //三秒之后抢庄
        sleep($this-> gtimeConfig['waitQZLong']);
        //机器人3或4秒后不抢庄
        $this->startRobotDoQiangz($gameId, $gameNo);

        // 抢庄====倒计时5秒钟
        $this->asycTimeStart($this-> gtimeConfig['QZLong'], $gameNo, $Parms, function () use ($gameNo, $gameRId, $gamePlays, $playFds, $fjInfo, $useCards,$roomEvery) {
            $error = '';
            $notQzUser = FALSE;
            if (! $fjInfo) {
                $fjInfo = BaseComm::GameRoomDetail($gameRId);
            }
            $gameData = BaseComm::distMemoryRooms($gameNo,FALSE);
            $firstStamp = isset($gameData['create']) ? intval($gameData['create']) : 0;
            $gameId = isset($fjInfo['gameId']) ? intval($fjInfo['gameId']) : 0;
            BaseEnum::Logger("选庄家定时器：Games-(PlaySanGong)-==========>  ，计算谁是[{$gameNo}]庄主---->>>" . json_encode($playFds), 'user-login'); // 所有玩家FD
            Timer::clear($this->baseOneTimer);
            // 计算谁是庄家；
            $minZjPoints = $gamePlays ? 5*$roomEvery*(sizeof($gamePlays)-1) : 0;//最小的庄家分数,保证其余玩家至少可以下1倍
            $zjUser = $this->countRoomMaimZhuang($gameNo, $gamePlays, $notQzUser,$minZjPoints);
            $zjUid = isset($zjUser['uid']) ? intval($zjUser['uid']) : 0; // 抢到倍数大于0
            $zjSeatid = isset($zjUser['seatNo']) ? intval($zjUser['seatNo']) : - 1; // 抢到倍数大于0
            $zjMuts = isset($zjUser['mutdotts']) ? intval($zjUser['mutdotts']) : 0; // 抢到倍数大于0
            $zjPoints = isset($zjUser['points']) ? floatval($zjUser['points']) : 0; // 抢到倍数大于0
            BaseEnum::Logger("抢庄统计：Games-(PlaySanGong)-哪些用户没有千抢庄 ===> " . json_encode($notQzUser), 'user-login');
            if (! empty($notQzUser)) {
                // 向所有玩家推送显示不抢庄的玩家
                foreach ($notQzUser as $onenotxj) {
                    //["seatNo"=> $ssid,"mutdotts" => 0, "self"=> 1]
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => BaseEnum::XYM_0X18,
                        "data" => $onenotxj
                    ])); // 推送不抢庄
                }
            }
            if (isset($zjUser) && $zjUid > 0 && isset($zjUser['fd']) && intval($zjUser['fd']) > 0 && ! empty($playFds) && $zjMuts > 0 && $zjPoints > 0) { // 抢zhuang 成功
                $totalNum = sizeof($playFds); // 通知给所有玩家，谁是庄家；
                $showList = array(
                    "seatNo" => $zjSeatid,
                    "mutdotts" => $zjMuts,
                    "max_mutle" => 10,
                    "nums" => $totalNum
                ); // 最大下注倍数
                   // 抢zhuang 成功； 计算每个用户最大倍数（要等玩家匹配成功才能计算的）；
                $maxBet_Mult = SanggEnum::countDeskMaxMutle($totalNum, $zjMuts, $zjPoints, $fjInfo);
                $showList["max_mutle"] = ($maxBet_Mult > 0) ? $maxBet_Mult : rand(5, 8);
                // 游戏记录写DB数据; ======> 记录玩家中谁是庄家及倍数；
                $savedata = array(
                    "ptype" => 1,
                    "userId" => $zjUid,
                    "data" => $zjMuts
                );
                $maxut = GameCommon::updateRoomsPInfo($gameNo, $savedata, $gamePlays, $error);

                // 抢成功才会到下一步
                if (isset($maxut) && $maxut === true) {
                    RedisTools::Pool_hDel(SysEnum::ONLINE_BDATA_KEY,$gameNo);    //抢庄数据处理清掉缓存里值
                    // 推送到所有FD，庄家的座位号；[XYM_0X19 --抢庄成功 ]
                    BaseEnum::Logger("抢庄成功：Games-(PlaySanGong)-恭喜用户 UID={$zjUid} 抢庄(QZ：{$zjMuts}倍)成功---->>> SUCCESS !!!!" . $gameNo, 'user-login');
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => BaseEnum::XYM_0X1A,
                        "data" => $showList
                    ])); // 推送相同内容
                    //TODO 获取起始时间间隔
                    $countStamp = BaseEnum::getNowTimeLong($firstStamp);
                    BaseComm::gameLogger($gameNo,"开局第{$countStamp}秒  , 定庄完成, {$zjSeatid} 号位为庄家 ({$zjMuts}倍),最高下注倍数：" . $showList["max_mutle"]);            //TODO 对局开始日志
                    $zjUserInfo = array(
                        "uid" => $zjUid,
                        "seatNo" => $zjSeatid,
                        "bet_mutle" => $zjMuts,
                        "main_flag" => 1
                    ); // 标识为庄主

                    // 启动下一个定时器；======> 闲家选倍数；
                    $robotMaxBet = $maxBet_Mult<3 ? $maxBet_Mult : 3;
                    $this->StartUserBetMuts($gameId, $gameRId, $gameNo, $robotMaxBet);
                } else {
                    // 异常失败
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => $maxut,//??推送false
                        "data" => null,
                        "msg" => $error
                    ])); // 推送相同内容
                }
            } else {
                BaseEnum::Logger('抢庄失败：PlaySanGong-(asycStartGame)-执行定时器计算抢庄失败 ---->>>Fail !!!!' . $gameNo, 'user-login');
            }
        });
    }





    /**
     * TODO 最高抢庄倍数计算
     * @param array $playPoints
     * @param number $roomEvery
     * @param number $roomMaxBet
     * @return boolean|number[]
     */
    protected function countPaiTimes($playPoints,$roomEvery = 1,$roomMaxBet = 15) {
        $countList = [];
        $maxUserQZList = [];
        $maxQzTimes = 1;//抢庄倍数
        $maxCardTimes = 5;

        //TODO 计算最高倍数； 牌型 :4倍  *  抢庄最高3倍* 底注,    不高于房间最大下注 15倍；
        if(!$playPoints || $roomEvery <= 0) return FALSE;
        foreach ($playPoints as $vsid => $onepoot){
            $maxPbt = floatval($onepoot / ($roomEvery * $maxCardTimes * $maxQzTimes ));
            if($maxPbt > 0){
                $countList[$vsid] = ($maxPbt > $roomMaxBet) ? $roomMaxBet : floor($maxPbt) ; //取玩家最高下注倍数
            }
        }

        //取最小值：minBet倍数；
        $playMinBets = !empty($countList) ? min($countList) : $roomMaxBet ;
        if ($playMinBets <= 0 || $playMinBets > $roomMaxBet) {
            $playMinBets = $roomMaxBet;
        }

        //TODO 计算每个玩家的最高抢庄倍数
        foreach ($playPoints as $osid => $onepoot){
            $maxQzBt  = round($onepoot / ($roomEvery * $playMinBets * $maxCardTimes ));   //最高抢庄倍数  = 余额分 / (房间底分 * 最高牌型14倍 * 玩家最小下注倍数)
            if (isset($maxQzBt) && intval($maxQzBt) > 0) {
                $maxQzBt = ($maxQzBt > $maxQzTimes) ? $maxQzTimes : $maxQzBt;
                $maxUserQZList[$osid] = $maxQzBt;
            }
        }
        //TODO 最高抢庄倍数计算
        BaseEnum::Logger("计算最高抢庄倍数:(countPaiTimes) 计算每个玩家最大下注倍数(最小值：{$playMinBets})，-->". json_encode($maxUserQZList), 'user-login');
        return $maxUserQZList;
    }
    
    /**
     * 游戏玩家下注实现(下注把倍数存入内存中处理)
     * @param string $gameNo
     * @param int $roomId
     * @param boolean $params
     */
    public function asycPlayBets($roomId,$gameNo,$params = FALSE,& $errorNo = -1){
        $userId = isset($params['loginUid']) ? intval($params['loginUid']) : 0 ;
        $qmutil = isset($params['qmutil']) ? intval($params['qmutil']) : 1 ; //下注倍数
        if (!$roomId || empty($gameNo) || empty($params) || $userId <= 0) {
            return  FALSE;
        }
        $gameDetail = BaseComm::distMemoryRooms($gameNo, FALSE);        // 内存数据；
        $fjStatus = isset($gameDetail['fjStatus']) ? intval($gameDetail['fjStatus']) : 0;
        $users = isset($gameDetail['lists']) ? $gameDetail['lists'] : FALSE;
        
        
        //庄家ID
        $zjUid = 0 ;
        if(!empty($users)){
            foreach ( $users as $oneuu ){
                if(isset($oneuu['uid']) && intval($oneuu['uid'])>0 && isset($oneuu['mainflag']) && intval($oneuu['mainflag'])==1){
                    $zjUid = intval($oneuu['uid']) ;
                    break;
                }
            }
        }
        
        
        BaseEnum::Logger("游戏数据 : (asycPlayBets - [{$gameNo}])==>" . json_encode($gameDetail), 'user-login');
        if (!$gameDetail || !$users) {
            $errorNo = BaseEnum::MSG_0XFA;
            return FALSE;
        }
        
        //非下注状态；
        if(!$fjStatus || $fjStatus !== 1 ){
            $errorNo = BaseEnum::MSG_0XFD;
            return FALSE;
        }
        
        //庄家不能下注
        if ($zjUid == $userId) {
            $errorNo = BaseEnum::MSG_0XF2;
            return FALSE;;
        }
        
        
        
        $userSeat = array_column($users, "seatNo","uid");
        $userFds = array_column($users, "fd","seatNo");
        
        //TODO 实现下注；写入数据进到内存中（结构:lists为玩家信息，bets 下注列表）
        $userBets  = isset($gameDetail['bets']) ? $gameDetail['bets'] :  [];
        $pushObj = FALSE;
        foreach ($userSeat as $uuid => $seatIndex){
            if ($uuid && intval($uuid) === $userId) {
                $userBets[$seatIndex] = $qmutil ; //下注倍数存起放在内存中
                $pushObj = [ "seatNo" => $seatIndex, "mutdotts" => $qmutil, "p_fd" => $userId];
                break;
            }
        }
        
        //下注数据存起来
        $gameDetail['bets'] = $userBets;
        BaseComm::distMemoryRooms($gameNo,TRUE,$gameDetail);
        
        // 下注信息
        $pushData = array( "m" => BaseEnum::XYM_0X19, "data" => $pushObj );
        BaseEnum::Logger("三公玩家下注成功 : (asycPlayBets - [{$gameNo}])==>" . json_encode($userBets), 'user-login');
        AuthCommon::pushFrontWeb($userFds, json_encode($pushData)); // 通知给所有玩家，谁在抢庄；
        
        //TODO  下注人员都满员启动提前结束定时器
        if(!empty($userBets) && sizeof($userBets) > 0 &&  sizeof($userBets) + 1 >= sizeof($userSeat)){
            PlayHelp::getInstance()->setCommTimerStop($gameNo,true);    //停掉定时器
            BaseEnum::Logger("所有玩家下注完成：========：(asycPlayBets) -- [ STOP ]-RoomId=". $gameNo ."  =======================设置为1,中断操作========>>>>>>", 'user-login');
        }
        
        return TRUE;
    }
    
    /**
     * 进入下一步处理事件,抢庄提前完成定时器结束前端动画完毕立刻发送指令服务器,如果没有发送指令服务器默认（动画前定时10秒执行）
     * @param $loginFd
     * @param $gameNo
     * @param bool $fjDetail
     * @param int $maxBet 机器人最大下注倍数
     * @return bool
     */
    public function doNextPlayBets($loginFd, $gameNo, $fjDetail = FALSE, $maxBet=3)
    {

        if(!$fjDetail){
            $fjDetail = BaseComm::distMemoryRooms($gameNo);
        }
        // 动画处理完触发；只能调用一次；触发动画倒计时；
        $gameId = isset($fjDetail['gameId']) ? intval($fjDetail['gameId']) : 0;
        $gameRid = isset($fjDetail['grid']) ? intval($fjDetail['grid']) : 0;
        $fjSta = isset($fjDetail['fjStatus']) ? intval($fjDetail['fjStatus']) : 0;
        $gamePlays = isset($fjDetail['lists']) ? $fjDetail['lists'] : FALSE; // 玩家列表；
        $playerFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playerFds,
            "status" => $fjSta
        ];
        $zjUserInfo = FALSE;
        if (! empty($gamePlays) && sizeof($gamePlays) >= 2) { // 查找庄家信息；
            foreach ($gamePlays as $oneuser) {
                if (isset($oneuser["uid"]) && intval($oneuser["uid"]) > 0 && isset($oneuser["mainflag"]) && intval($oneuser["mainflag"]) === 1) { // 庄家 mainflag = 1
                                                                                                                                                  // 庄家的倍数
                    $zjUserInfo = array(
                        "uid" => $oneuser["uid"],
                        "seatNo" => @$oneuser["seatNo"],
                        "bet_mutle" => isset($oneuser['mutdotts']) ? intval($oneuser['mutdotts']) : 0,
                        "main_flag" => 1 // 标识为庄主;
                    );
                    break;
                }
            }
        }

        // 标识为庄主;
        if (! $zjUserInfo || ! isset($zjUserInfo['uid']) || intval($zjUserInfo['uid']) <= 0)
            return FALSE;

        //TODO 开启机器人自动下注功能
        $this->startRobotDoBets($gameId,$gameRid, $gameNo,$maxBet);

        $this->asycTimeStart($this->gtimeConfig['betLong'], $gameNo, $Parms, function () use ($gameNo, $gamePlays, $playerFds, $fjDetail, $zjUserInfo) {
            $userBetInfo = [];
            $zjUserid = isset($zjUserInfo["uid"]) ? intval($zjUserInfo["uid"]) : 0;
            $gameId = isset($fjDetail["gameId"]) ? intval($fjDetail["gameId"]) : 0; // 游戏ID值；
            $gameRId = isset($fjDetail["grid"]) ? intval($fjDetail["grid"]) : 0; // 房间ID值；
            $useCards = isset($fjDetail["frontCards"]) ? $fjDetail["frontCards"] : FALSE; // 提前发的牌数据
            $firstStamp = isset($fjDetail["create"]) ? intval($fjDetail["create"]) : 0;

            //TODO 获取起始时间间隔
            $countStamp = BaseEnum::getNowTimeLong($firstStamp);
            //房间内的数据
            $gameDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userBets  = isset($gameDetail['bets']) ? $gameDetail['bets'] :  [];            //下注的数据内容
            $gamePlays = isset($gameDetail['lists']) ? $gameDetail['lists'] : FALSE;        // 玩家列表；
            
            $allSeat = array_column($gamePlays, 'seatNo',"uid");

            $betLoggs=["开局第{$countStamp}秒  , 下注"];
            /**
             * TODO 下注==== 玩家下注TO DB
             * 实际步骤：
             * 1、检查所有玩家是否有下注和下注倍数据
             * 2、把没有下注完的默认下1倍；并推给所有玩家
             */
            BaseEnum::Logger("执行定时器计算：PlaySanGong-(asycStartUserBetMuts)-=====[投注倍数]  ，去列队中给[{$gameNo}]所有玩家下单--（DB）-->>>" . json_encode($playerFds), 'user-login');
            BaseEnum::Logger('取内存数据：PlaySanGong-[asycStartUserBetMuts]--->>>' . json_encode($gameDetail), 'user-login');
            
            
            $userBetIds = [];
            $noticeUsers = [];
            //TODO 计算未下注的用户信息
            foreach ($allSeat as $uuid => $setid2){
                if (isset($uuid) && intval($uuid)>0 && intval($uuid) === $zjUserid) continue;
                $usrbetMul = isset($userBets[$setid2]) ? intval($userBets[$setid2]) : 0;        //下注倍数
                if($uuid > 0 && $usrbetMul <= 0 ){
                    $usrbetMul = 1;
                    $userBets[$setid2] = 1 ;
                    $noticeUsers[$uuid] = array("uid" =>$uuid,"seatNo" =>$setid2, "bet_mutle" => 1);        //未下注
                }
                $betLoggs[] = "{$setid2} 号位  下注{$usrbetMul} 倍";
                $userBetIds[] = $uuid;   //下注列表
            }
            
            
            //TODO 修改内存中游戏状态
            foreach ($gamePlays as $setiid => &$oneplay) {
                if (isset($userBets[$setiid]) && intval($userBets[$setiid]) > 0) {
                    $oneplay["mutdotts"] = intval($userBets[$setiid]);       // 修改下注倍数
                    $oneplay["pstatus"] = CardEnum::GAME_STEP_2;             // 修改下注成功；
                }
            }
            $gameDetail['bets'] = $userBets;
            $gameDetail['fjStatus'] = CardEnum::GAME_STEP_2;                // 下注成功
            $gameDetail['lists'] = $gamePlays;
            BaseComm::distMemoryRooms($gameNo,TRUE,$gameDetail);            //TODO 存储游戏数据
            BaseEnum::wirteRedisData(SysEnum::ONLINE_ROOMS_LIST_KEY . $gameNo, json_encode($gameDetail));
            
            $error = -1;
            
            //TODO 所有玩家订单入库处理： (闲家下注)
            $savedata = array("ptype"=> 2 ,"userId" => implode(',', $userBetIds) ,"data"=> $userBets);
            $dbFlag = GameCommon::updateRoomsPInfo($gameNo,$savedata,$gamePlays,$error);  //下注成功；
            
            if ($dbFlag !== TRUE) {
                BaseEnum::Logger("闲家下注失败：(下注) ->>> ERROR -- {$error}，  未下注玩家：" . json_encode($noticeUsers), 'user-login');
                $userBetInfo[$zjUserid] = $zjUserInfo; // 合并庄家的ID
                return FALSE;
            }

            BaseComm::gameLogger($gameNo,$betLoggs);   //下注日志
            // TODO 单个数据推到前端；
            $allFds = array_column($gamePlays, "fd","seatNo");
            if (! empty($noticeUsers)) {
                $noticeUsers = array_column($noticeUsers, null, "seatNo");  // 通知给所有玩家，下注倍数；
                foreach ($noticeUsers as $siteid => $oneline) {
                    $oneInfo = [ "seatNo" => $siteid, "mutdotts" => isset($oneline['bet_mutle']) ? intval($oneline['bet_mutle']) : 7, "self" => 1];
                    $pushdata = ['m' => BaseEnum::XYM_0X19, "data" => $oneInfo];
                    AuthCommon::pushFrontWeb($allFds, json_encode($pushdata));   // 推送未下注玩家默认1倍
                }
            }
            // TODO 开始发牌:
            BaseEnum::Logger("启动发牌：(只发每个人的手牌) ->>> Start，  INFO：" . json_encode([$gameId, $gameRId, $gameNo]), 'user-login');
            $this->StartCards($gameId, $gameRId, $gameNo, $allFds, $useCards);

        });
    }

    /**
     * 掉线重连操作
     *
     * @param int $userid
     * @param int $loginFd
     * @param string $newGameNo
     */
    public function reConnectPlay($userid, $loginFd, $gameNo = FALSE)
    {
        if (! $gameNo || $userid <= 0)
            return FALSE; // 玩家最新游戏ID对应的号
        $fjData = BaseComm::distMemoryRooms($gameNo, FALSE);
        $gameId = isset($fjData['gameId']) ? intval($fjData['gameId']) : 0;
        $gameStatus = isset($fjData['fjStatus']) ? intval($fjData['fjStatus']) : 0;
        $gamePlays = isset($fjData['lists']) ? $fjData['lists'] : FALSE;
        // 只要游戏没有结束就换掉用户的客户端FD值，否则推送出错；
        if (! empty($gamePlays)) {
            foreach ($gamePlays as $r => $oneline) {
                if (isset($oneline['uid']) && intval($oneline['uid']) === $userid) {
                    $gamePlays[$r]['fd'] = $loginFd; // 当前登录用户的客户FD值；
                }
            }
            $fjData['lists'] = $gamePlays; // 修改后的数据重新给值
            BaseComm::distMemoryRooms($gameNo, TRUE, $fjData); // 保存数据
                                                               // 游戏数据恢复
            BaseEnum::Logger("掉线重连：PlaySanGong --> reConnectPlay-[{$userid},$gameId ,$gameNo]-------gameData-->" . json_encode($fjData), 'user-login');
            // 查询当前游戏状态：
            if (! empty($fjData) && $gameStatus >= 0 && in_array($gameStatus, [
                0,
                1,
                2,
                3,
                4,
                5
            ])) { // 大于1 都是游戏中；
                $steps = BaseEnum::GAME_STEP;
                $stepName = isset($steps[$gameStatus]) ? $steps[$gameStatus] : "-";
                BaseEnum::Logger("掉线重连：PlaySanGong --> 当前状态：-[{$stepName},$gameNo]-------status-->" . $gameStatus, 'user-login');
                // 显示游戏中的数据结构：定义新的结构；
                $returnData = array(
                    "gameNo" => $gameNo,
                    "step" => $stepName,
                    "status" => $gameStatus,
                    "lists" => []
                );
                // 恢复游戏数据： 只处理以下几张情况；
                // 1、抢庄中---谁庄过庄（标识出来），
                // 2、下注中(谁是庄家标识出来，)
                // 3、结算中(庄家，下注倍数，当前玩家牌值内容)
                $gameResult = $this->reBackData($userid, $gameStatus, $gameNo, $gamePlays);
                BaseEnum::Logger("掉线重连：PlaySanGong --> 数据恢复：-[{$gameNo}]-------status-->" . json_encode($gameResult), 'user-login');
                if (! $gameResult) {
                    return FALSE;
                }
                // 显示每个玩家的数据内容；
                $returnData["lists"] = $gameResult;
                return $returnData;
            }
        }
        return FALSE;
    }

    /**
     * 恢复游戏数据；
     * 处理以下几张情况；
     * 1、抢庄中---谁庄过庄（标识出来），
     * 2、下注中(谁是庄家标识出来，)
     * 3、结算中(庄家，下注倍数，当前玩家牌值内容)
     *
     * 附状态值：0 => '匹配', 1 => '抢庄', 2 => '下注', 3 => '发牌', 4 => '翻牌', 5 => '结算',
     *
     * @param int $gameStatus
     * @param array $gamePlays
     */
    protected static function reBackData($loginUid, $gameStatus, $gameNo = FALSE, $gamePlays = FALSE)
    {
        if (! $loginUid || ! $gamePlays || ! $gameNo)
            return false;
        $redisobj = new RedisTools();
        $redisobj->select(0);
        $palyUser = $gamePlays;
        foreach ($palyUser as & $oneus) {
            unset($oneus['fd']);
            unset($oneus['agentId']);
            unset($oneus['betmoney']);
        }
        // 匹配成功 开始抢庄 ===> 谁有抢庄
        if ($gameStatus === CardEnum::GAME_STEP_0) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '玩家抢庄';
            }
        } // 抢庄完成 开始下注 ===> 标出谁是庄家,闲家下注倍数；
        else if ($gameStatus === CardEnum::GAME_STEP_1) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '闲家下注';
                if (isset($oneuser['mainflag']) && intval($oneuser['mainflag']) == 1) { // 定庄：uid,
                    $palyUser[$sid]['text'] = '庄';
                    $palyUser[$sid]['pstatus'] = '等待闲家下注';
                } else {
                    $palyUser[$sid]['text'] = '闲';
                    $palyUser[$sid]['mutdotts'] = isset($betArray[$sid]) ? intval($betArray[$sid]) : 0; // 闲家下注倍数
                    $palyUser[$sid]['max_mutle'] = 15; // 最大下注倍数；
                }
            }
        } // 下注完成 开始发牌 翻牌 ===> 开始发牌（显示下注倍数）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_2,
            CardEnum::GAME_STEP_3
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo, FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = ($gameStatus == 3) ? "翻牌中" : '发牌中';
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = false; // 已发牌
                if (isset($oneuser['uid']) && intval($oneuser['uid']) == $loginUid) { // 显示发给我的手牌；
                    $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];
                }
            }
        } // 翻牌完成 摊牌 ===> 结算数据（显示玩家最后的结算数据）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_4,
            CardEnum::GAME_STEP_5
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo, FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = "结算中";
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];

                // 显示结算所的金额数据；
                $palyUser[$sid]['lastmoney'] = 0.01;
            }
        }
        return $palyUser;
    }

    /**
     * 异步监控房间内下注
     * asycStartUserBetMuts
     */
    protected function StartUserBetMuts($gameId, $gameRId, $gameNo, $maxBet=3)
    {
        BaseEnum::Logger('闲家异步统计：PlaySanGong-(StartUserBetMuts)-统计 ---->>>>>>>>>>>>> 待完善:' . $gameNo, 'user-login');
        // 抢庄完成，8秒动画效果;
        Timer::after($this->gtimeConfig['waitBetLong']*1000, function () use ($gameNo, $gameId,$maxBet) {
            $fjDetail = BaseComm::distMemoryRooms($gameNo); // 房间内的信息；

            // 查看当前状态是否启动；
            if (isset($fjDetail["doNext"]) && intval($fjDetail["doNext"]) > 0) { // 已经处理过了；
                BaseEnum::Logger('异步自动下注执行：PlaySanGong-(StartUserBetMuts)-[检查到doNext=1 已经执行处理过，不再处理]--->>>' . json_encode($fjDetail), 'user-login');
            } else {
                $fjDetail["doNext"] = 1;
                BaseComm::distMemoryRooms($gameNo, true, $fjDetail); // 保存标识不允许再次发起
                $this->doNextPlayBets(null, $gameNo, $fjDetail, $maxBet);
            }
        });
    }

    /**
     * 开始发牌操作；
     *
     * @param array $paramList
     */
    protected function StartCards($gameId, $gameRId, $room_No, $playerFds = false, $useCards = FALSE)
    {
        $playerCards = [];
        $getAlldata = BaseComm::distMemoryRooms($room_No, FALSE);
        BaseEnum::Logger('取内存数据：PlaySanGong--[StartCards]--->>>' . json_encode($getAlldata), 'user-login');
        $gamePlays = $getAlldata['lists'] ?? FALSE;
        $firstStamp = isset($getAlldata["create"]) ? intval($getAlldata["create"]) : 0;
        if(empty($gamePlays)){
            BaseEnum::Logger("游戏数据异常推送：PlayNiuNiu-(StartCards)-{$gameRId}==>{$room_No}|data : " . json_encode($gamePlays), 'user-login');
            return FALSE;
        }
        $playerFds = array_column($gamePlays ,"fd", "seatNo"); // 使用最新数据
        $playerMoneys = array_column($gamePlays, "points", "seatNo"); // 使用最新数据
        // 启动发牌；======> 操作代码 ： XYM_0X19；
        if (empty($useCards)) {
            BaseEnum::Logger("重新启动发牌：PlaySanGong-(StartCards)-；===={$gameRId}==>{$room_No}| XYM_0X19 --> ==allUserFds : " . json_encode($playerFds), 'user-login');
            $useCards = GameCommon::createCardList($gameId, $room_No, false);
        } else {
            BaseEnum::Logger("发牌推送：PlaySanGong-(StartCards)-；===={$gameRId}==>{$room_No}| XYM_0X19 --> ==data : " . json_encode($useCards), 'user-login');
        }
        //处理牌型等级
        if (isset($useCards) && ! empty($useCards)) {
            $long = BaseEnum::getNowTimeLong($firstStamp);
            BaseComm::gameLogger($room_No,"开局第{$long}秒 , 发玩家手牌");
            foreach ($useCards as $pushOneMsg) {
                $seatId = isset($pushOneMsg['seatNo']) ? intval($pushOneMsg['seatNo']) : 0;
                $curUser = $gamePlays[$seatId] ?? false;
                $curUpoint = $curUser['points'] ?? false;
                if ($seatId !== false && $seatId >= 0 && isset($pushOneMsg['cards']) && ! empty($pushOneMsg['cards']) && $curUser) {
                    $oneCards = $pushOneMsg['cards'];
                    $niuLevel = 0;
                    $levelRes = SanggEnum::dealSanggLevel($oneCards,$niuLevel);
                    //将牌型数据存入内存
                    $curUser['cards'] =  $oneCards;
                    $curUser['cardsLevel'] = $levelRes['key'] ?? 1;
                    $curUser['cardsMutle'] = $levelRes['mutl_value'] ?? 1;
                    $curUser['pstatus'] = CardEnum::GAME_STEP_3;
                    $gamePlays[$seatId] = $curUser;

                    //传递数组
                    $pushWjInfo = [
                        "seatNo" => $seatId,
                        "cards" => $oneCards,
                        "cardsLevel" => $levelRes['key'],
                        "cardsMutle" => $levelRes['mutl_value'],
                        "userPoints"=> $curUpoint,
                    ];
                    $playerCards[$seatId] = $pushWjInfo;
                }
            }
            $getAlldata['fjStatus'] = CardEnum::GAME_STEP_3; // 修改为发牌成功；
            $getAlldata['lists'] = $gamePlays;
            BaseComm::distMemoryRooms($room_No, TRUE, $getAlldata); // 保存用户数据

            foreach ($playerFds as $siteid => $fd) {                    // 开始翻牌
                $oneInfo = [
                    'seatNo' => $siteid,
                    'text' => '开始翻牌'
                ];
                $pushdata = [
                    'm' => BaseEnum::XYM_0X1B,
                    'data' => $oneInfo
                ];
                AuthCommon::pushFrontWeb($fd,json_encode($pushdata));
            }

            $this->asycWaitDealCenter($gameRId, $room_No, $playerCards, $playerFds);
        } else {
            BaseEnum::Logger('发牌失败：PlaySanGong-(asycStartCards)-发牌；======>   失败 Fail !! -->  ' . $room_No, 'user-login');
        }
    }

    /** 机器人翻牌操作
     * @param $gameId
     * @param $gameNo
     * @return bool
     */
    public function startRobotDoFlipCard($gameRid,$gameNo)
    {
        //TODO 机器人列表翻牌操作
        $allRobotUsers=PlayCommon::getGameRobotsUser($gameRid,$gameNo);
        $robot_num = !empty($allRobotUsers) ? sizeof($allRobotUsers) : 0;
        BaseEnum::Logger("机器人翻牌：GameId-{$gameRid} ,当前局[{$gameNo}] 共有{$robot_num}个机器人>" . json_encode($allRobotUsers), 'user-login');          //推送倒计时显示数

        //TODO 机器人列表(数据处理)
        if (!empty($allRobotUsers) && $robot_num > 0) {
            $sleepTime = rand(1,2); //TODO 启动 翻牌操作
            Timer::after($sleepTime * 1000, function() use($gameNo,$allRobotUsers) {
                $pushMsg = [];  //下注操作
                $gameDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
                $allPlayer = $gameDetail['lists'] ?? FALSE;
                $allClientFds = !empty($allPlayer) ? array_column($allPlayer, "fd","seatNo") : FALSE;
                $gameDetail['fjStatus'] = CardEnum::GAME_STEP_4; // 修改为拼牌牌；
                //所有玩家都推送
                if(!$allRobotUsers || !$gameNo || !$gameDetail || !$allClientFds) return false;
                foreach ($allRobotUsers as $obj){
                    $curUfd = $obj['fd'] ?? 0;
                    $seatIndex = $obj['seatNo'] ?? 0;
                    if($seatIndex >= 0 && isset($obj['uid']) && $curUfd > 0){
                        $pushMsg[] = [
                            'seatNo' => $seatIndex,
                            "cards" => $obj['cards'],
                            "cardsLevel" => $obj['cardsLevel'],
                            'cardsMutle' => $obj['cardsMutle'],
                            'status' => 1,
                            'text' => '已翻牌'
                        ];
                    }
                }
                BaseEnum::Logger("机器人翻牌：GameNo-[{$gameNo}]  推送数据 >> " . json_encode($pushMsg), 'user-login');
                if (!empty($pushMsg)) {
                    //推送数据
                    foreach ($pushMsg as $seatNo => $onedata){
                        @usleep(600*1000);
                        $onePush = ["m"=> BaseEnum::XYM_0X26 , "data"=> $onedata];
                        AuthCommon::pushFrontWeb($allClientFds,json_encode($onePush));
                    }
                    //推送完成统一修改状态
                    $gameDetail = BaseComm::distMemoryRooms($gameNo,FALSE);//推送完再取内存。
                    $allPlayer = $gameDetail['lists'] ?? FALSE;
                    foreach ($allRobotUsers as $obj){
                        $seatNo = $obj['seatNo'] ?? 0;
                        $currUser = $allPlayer[$seatNo] ?? false;
                        isset($currUser['pstatus']) && $currUser['pstatus'] = CardEnum::GAME_STEP_4;
                        $allPlayer[$seatNo] = $currUser;
                    }
                    $gameDetail['lists'] = $allPlayer; //翻牌数据修改
                    BaseComm::distMemoryRooms($gameNo,TRUE,$gameDetail);

                    $flipedSeat = [];
                    foreach ($allPlayer as $seatNo => $obj) {
                        if (isset($obj['pstatus']) && intval($obj['pstatus']) == CardEnum::GAME_STEP_4) {
                            $flipedSeat[] = $seatNo;//已经翻牌的座位号
                        }
                    }
                    if (!empty($flipedSeat) && sizeof($flipedSeat) == sizeof($allPlayer)){
                        PlayHelp::getInstance()->setCommTimerStop($gameNo,true);//所有玩家都已经翻牌停掉定时器
                        BaseEnum::Logger("所有玩家翻牌完成", 'user-login');
                    }

                }
            });
        }
        return FALSE;
    }

    /**
     * 翻牌结算处理；
     *
     * @param string $room_No
     * @param array $useCards
     * @param boolean $playerFds
     */
    protected function asycWaitDealCenter($gameRId, $gameNo, $useCards, $playerFds = FALSE)
    {
        $gameAllData = BaseComm::distMemoryRooms($gameNo, FALSE); // 内存数据；
        $fjSta = isset($gameAllData['fjStatus']) ? intval($gameAllData['fjStatus']) : 0;
        $gameId = isset($gameAllData['gameId']) ? $gameAllData['gameId'] : 0;
        $gamePlays = isset($gameAllData['lists']) ? $gameAllData['lists'] : FALSE; // 玩家列表；
        $playerFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playerFds,
            "status" => $fjSta
        ];
        //翻牌过程
        sleep(1);
        //机器人翻牌
        $this->startRobotDoFlipCard($gameId,$gameNo);
        $this->asycTimeStart($this->gtimeConfig['waitCardLong'], $gameNo, $Parms, function () use ($gameNo, $playerFds,$useCards) {
            Timer::clear($this->baseOneTimer); // 推送谁还没有完成的；
            $fjDetail = BaseComm::distMemoryRooms($gameNo, FALSE);
            $betList = isset($fjDetail['lists']) ? $fjDetail['lists'] : false;
            $firstStamp = isset($fjDetail["create"]) ? intval($fjDetail["create"]) : 0;
            $long = BaseEnum::getNowTimeLong($firstStamp);
            BaseComm::gameLogger($gameNo,"开局第{$long}秒 , 玩家翻牌");
            // 下边玩家有几个还没推送翻牌的操作；
            $notPinfds = [];
            if (! empty($betList)) {
                // FD防变动
                $playerFds = ! empty($betList) ? array_column($betList, "fd", "seatNo") : false; // 使用最新数据
                BaseEnum::Logger('翻牌数据查找：PlaySanGong-(BaseDB::asycWaitDealCenter)-是否有未翻牌的：[asycWaitDealCenter]--->>>' . json_encode($betList), 'user-login');
                foreach ($betList as $siteid => $onep) {
                    if (isset($onep['pstatus']) && intval($onep['pstatus']) !== CardEnum::GAME_STEP_4 && isset($onep['fd'])) { // 还没翻牌的玩家
                        $notPinfds[] = $siteid;
                    }
                }
                if (! empty($notPinfds)) {
                    foreach ($notPinfds as $seatNo) {
                        $oneCards = $useCards[$seatNo] ?? false;
                        $oneInfo = [
                            'seatNo' => $seatNo,
                            "cards" => $oneCards['cards'],
                            "cardsLevel" => $oneCards['cardsLevel'],
                            'cardsMutle' => $oneCards['cardsMutle'],
                            'status' => 1,
                            'text' => '已翻牌'
                        ];
                        isset($betList[$seatNo]) && $betList[$seatNo]['pstatus'] = CardEnum::GAME_STEP_4;
                        AuthCommon::pushFrontWeb($playerFds, json_encode([
                            'm' => BaseEnum::XYM_0X26,
                            "data" => $oneInfo
                        ])); // 推送
                    }
                    $fjDetail['lists'] = $betList;
                    BaseComm::distMemoryRooms($gameNo, TRUE,$fjDetail); // 保存用户数据
                }
            }
        });

        // 计算====倒计时5秒钟;
        Timer::after($this->gtimeConfig['waitDealLong']*1000, function () use ($gameRId, $useCards, $gameNo, $playerFds) {
            $allCards = [];
            $allUserIds = [];
            // 房间信息
            $roomDetail = BaseComm::GameRoomDetail($gameRId);
            $gameId = $roomDetail["gameId"] ?? 0;
            // 棋牌内容：
            $fjDetail = BaseComm::distMemoryRooms($gameNo, FALSE);
            $userbetList = false;
            $firstStamp = isset($fjDetail["create"]) ? intval($fjDetail["create"]) : 0;
            if (! empty($fjDetail) && isset($fjDetail['lists'])) {
                $userbetList = $fjDetail['lists'];
                $playerFds = ! empty($userbetList) ? array_column($userbetList, "fd", "seatNo") : false; // FD防变动
                $allUserIds = array_column($userbetList, "uid");
            }
            BaseEnum::Logger("三公结算处理：PlaySanGong-(asycWaitDealCenter)-[roomid={$gameRId}]；======> Start ....-->UserList=" . json_encode($userbetList), 'user-login');
            BaseEnum::Logger("三公结算：PlaySanGong-(asycWaitDealCenter)-[roomid={$gameRId}]；======> getRoomInfo=" . json_encode($roomDetail), 'user-login');

            // 座位号
            $uSeatList = ! empty($userbetList) ? array_column($userbetList, null, 'seatNo') : false;

            // 比牌数据操作；$useCards
            $zjObject = false;
            if (! empty($useCards) && ! empty($uSeatList) && ! empty($userbetList)) {
                foreach ($useCards as $seatId => $cardinfo) {
                    $allCards[$seatId] = isset($cardinfo["cards"]) ? $cardinfo["cards"] : false; // 取牌数据
                    $useFo = isset($uSeatList[$seatId]) ? $uSeatList[$seatId] : false;
                    $useCards[$seatId]["userId"] = isset($useFo['uid']) ? intval($useFo['uid']) : 0;
                    $useCards[$seatId]["mainFlag"] = isset($useFo['mainflag']) ? intval($useFo['mainflag']) : 0; // 庄家标识
                    $useCards[$seatId]["mainMutle"] = isset($useFo['mutdotts']) ? intval($useFo['mutdotts']) : 1; // 下注或抢庄的倍数关系
                    if ($useCards[$seatId]["mainFlag"] === 1) {
                        $zjObject = $useCards[$seatId];
                        // 处理一下倍数关系统；至少1倍 mainMutle
                        unset($useCards[$seatId]); // 庄家牌内容
                    }
                }

                // 结算处理；
                BaseEnum::Logger('三公庄家：PlaySanGong-(asycWaitDealCenter)===-->' . json_encode($zjObject), 'user-login');
                BaseEnum::Logger('三公闲家：PlaySanGong-(asycWaitDealCenter)===-->' . json_encode($useCards), 'user-login');

                $realUserNotices = [];
                //TODO  结算玩家的计算；把庄家跟闲家进行一一对比；
                $resultList = GameCommon::dealPlayMoney($gameRId, $gameNo, $zjObject, $useCards, $roomDetail,$realUserNotices); // 结算内容
                // 推送：所有牌数据和输赢；
                if (! empty($resultList) && sizeof($resultList) > 1) {
                    $gameDoRealNum = sizeof($resultList);
                    BaseEnum::Logger('三公结算处理：PlaySanGong-(asycWaitDealCenter)-；======> SUCCESS ....-->  ' . json_encode($resultList), 'user-login');
                    $fjDetail['fjStatus'] = CardEnum::GAME_STEP_5;
                    if (isset($fjDetail['lists']) && ! empty($fjDetail['lists'])) {
                        foreach ($fjDetail['lists'] as $setiid => $fg) {
                            $fjDetail['lists'][$setiid]["pstatus"] = CardEnum::GAME_STEP_5;
                        }
                    }
                    //TODO 获取起始时间间隔
                    $countStamp = BaseEnum::getNowTimeLong($firstStamp);
                    $gameLoggs= ["开局第{$countStamp}秒 , 结算"];
                    BaseComm::distMemoryRooms($gameNo, TRUE, $fjDetail); // 保存用户数据
                    BaseEnum::wirteRedisData(SysEnum::ONLINE_ROOMS_LIST_KEY . $gameNo, json_encode($fjDetail)); // 缓存；

                    $pushArr = [];// 处理结果；谁赢钱；
                    foreach ($resultList as $v) {
                        $seatNo = $v['seatNo'];
                        $cellScore = $v['cellScore'] ?? 0;
                        $changeMoney = $v['changeMoney'] ?? 0;
                        $oneCards = isset($allCards[$seatNo]) ? $allCards[$seatNo] : [];
                        $pushArr[$seatNo] = [
                            'seatNo' => $seatNo,
                            'uid' => $v['uid'],
                            'mainFlag' => isset($uSeatList[$seatNo]['mainflag']) ? $uSeatList[$seatNo]['mainflag'] : 0,
                            'points' => $v['points'],
                            'changeMoney' => $changeMoney,
                        ];
                        $gameLoggs[] = "{$seatNo} 号位  本局输赢:{$changeMoney},下注分：{$cellScore},牌值：".json_encode($oneCards);
                    }
                    // 前端结算：
                    AuthCommon::pushFrontWeb($playerFds, json_encode([
                        'm' => BaseEnum::XYM_0X1C,
                        "data" => array_values($pushArr)
                    ])); // 推送不同的数据；
                    //TODO 在线玩家数据（游戏结束，在线人数减少）
                    BaseComm::changeOnLines($gameId,$gameDoRealNum,1);
                    BaseComm::distLastGameNoListRedis($allUserIds,TRUE,FALSE); //清掉最新局
                    PlayCommon::doBackFreeRobot($gameId,$allUserIds);
                    PlayCommon::gameNoticeSaveCache($gameId,$gameNo,$realUserNotices);                          //TODO 加入游戏通知列表
                    BaseComm::gameLogger($gameNo,$gameLoggs,["finish"=>TRUE]);
                    return TRUE;
                } else {
                    BaseEnum::Logger('三公结算处理：结算失败 ！！！！PlaySanGong-(asycWaitDealCenter)-；======>  ' . print_r($zjObject, true), 'user-login');
                    return false;
                }
            }
        });
    }
}

?>